/*----------------------------------------------------------------------------
Owner(s): Shane Whitfield
$Copyright: $
$Id: 

Purpose  : Basic game object
----------------------------------------------------------------------------*/

#pragma once

#include "core.h"
#include "bbmath.h"
#include "model.h"
#include "gomgr.h"
#include <vector>

class CProgressBar;

/*--------------------------------------------------------------------------*/
// Class CGo declaration.
class CGo
{
public:

					CGo();
	virtual EClass	GetClass() = 0;

	//Events
	virtual void	Render();
	virtual void	Update();
	virtual bool	IsPointWithin(const Vector2f& i_pos);
	
	virtual void	OnPreWorldUnload() {}
	virtual void	onDeath(){}
	
	//ID Check: $$$$ Later this should be changed to something way better (maybe an enum?)
	virtual bool	IsNode() const {
						return false; }
	virtual bool	IsEnemy() const {
						return false; }
	virtual bool	IsMinerals() const {
						return false; }
						
	void			SetColor(const Color4f& i_color) {
						m_model->SetColor(i_color); } 
	Color4f			GetColor() {
						return m_model->GetColor(); } 
	void			SetAlpha(float i_alpha) {
						m_model->SetAlpha(i_alpha); }
	
	bool			IsAlive() const {
						return m_state != EState_Dead; }
	bool			IsDead() const {
						return m_state == EState_Dead; }
	Vector2f		GetPos() const {
						return m_worldMat.GetPos(); }
	const Transform2D	GetTransform() const {
							return m_worldMat; }
	void			SetPos(const Vector2f& i_newPos);
	float			GetHealth() const {
						return m_curHealth; }
	bool			HasFullHealth() const {
						return m_maxHealth <= m_curHealth; }
	void			Damage(float i_damageValue);
	void			Heal(float i_healValue);
	float			GetBoundingRadius() const {
						return m_model->GetBoundingRadius(); }
	void			SetBoundingRadius(float i_radius) {
						m_model->SetBoundingRadius(i_radius); }
	void			SetTexture(const char* i_texture) {
						m_model->SetTexture(i_texture); }
	virtual void	Spawn(const Vector2f& i_pos) {
						SetPos(i_pos); }
	bool			IsInWorld() const {
						return m_worldState == EWorldState_In; }
	virtual void	RemoveFromWorld() {
						m_worldState = EWorldState_Out; }
	void			AddToWorld() {
						m_worldState = EWorldState_In; }
	virtual bool    IsPlacing() const {
                        return false;  }
		
    void            SetDepthLayer(EDepthLayer i_depthlayer) {
                        m_depthLayer = i_depthlayer;
                        calcActualDepthFromDepthEnum();}
    
    EDepthLayer     GetDepthLayer() const {
                        return m_depthLayer;}
    
    
 
protected:

	virtual	void	on_TouchFocusGained(const Vector2f& i_touchPos, bool& o_usedInput){};
	virtual	void	on_TouchFocusMoved(const Vector2f& i_touchPos, bool& o_usedInput){};
	virtual	void	on_TouchFocusLost(const Vector2f& i_touchPos, bool& o_usedInput){};
	virtual bool	doesHandlesTouch() const {
						return false; }

    void            calcActualDepthFromDepthEnum();
    
private:
	
	enum EState
	{
		BEGIN_ENUM(EState_),
		
		EState_Alive,
		EState_Dead,
		
		END_ENUM(EState_)
	};
	
	enum EStateContact
	{
		BEGIN_ENUM(EStateContact_),
		
		EStateContact_None,
		EStateContact_Hoovering,
		
		END_ENUM(EStateContact_)
	};
	
	enum EWorldState
	{
		EWorldState_In,
		EWorldState_Out
	};
	

	void		setState(EState i_state);
	
	CProgressBar*	m_healthProgress;
	EState			m_state;
	Transform2D		m_worldMat;
	float			m_boundingRadius;
	CModel*			m_model;
	float			m_curHealth;
	float			m_maxHealth;
	bool			m_isVisible;
	EWorldState		m_worldState;
    EDepthLayer     m_depthLayer;
};

/*--------------------------------------------------------------------------*/
// Class CGoMinerals declaration.
class CGoMinerals : public CGo
{
	typedef CGo super;
	
public:
					CGoMinerals();
		
	//CGo Overrides
	virtual EClass	GetClass() {
						return EClass_Minerals;}
	virtual void	Update();

	bool			IsMinerals() const {
						return true; }
	bool			IsEmpty() const {
						return m_state == EState_Empty; }
	float			Mine(float amount);
	void			SetMineralCount(float i_count) {
						m_mineralCount = i_count; }

private:

	enum EState
	{
		EState_Empty,
		EState_Small,
		EState_Medium,
		EState_Large,
	};
	
	void	setState(EState i_state);
	void	setStateFromMineralCount();
	
	EState	m_state;
	float	m_mineralCount;

};

/*--------------------------------------------------------------------------*/
// Class CGoNode declaration.
class CGoNode : public CGo
{

	typedef CGo super;
	
public:

	CGoNode();

	//CGo overrides
	virtual void	Render();
	virtual void	Update();
	virtual void	RemoveFromWorld();
	
	virtual void	OnConnectionGained(CGoNode* i_nodeGained);
	virtual void	OnConnectionSevered(const CGoNode* i_severedNode);
	
	virtual bool	IsNode() const {
						return true; }
	bool			HasConnectionSlot() const;
	float			GetConnectionRadius() const {
						return m_connectionRadius; }
	bool			DoesProvideConnection() const {
						return m_connectionFlags.Provides; }
	bool			DoesRequiresConnection() const {
						return m_connectionFlags.Requires; }
	bool			IsConnected() const {
						return m_state == EState_Connected; }
    bool            IsPlaced() const {
                        return m_state != EState_Placing;  }
	virtual bool    IsPlacing() const {
                        return m_state == EState_Placing;  }
	bool			IsConstructed() const {
						return m_state != EState_Constructing; }
	float			GetConstructionTime() const {
						return m_constructionTime; }
	void			SetConstructionTime(float i_constructionTime) {
						m_constructionTime = i_constructionTime; }
						
	//NodeMgr APIs
	bool			HasNodeBeenVisited() const {
						return m_hasNodeVisited; }
	void			VisitNode() {
						m_hasNodeVisited = true; m_isOrphanedFromRoot = false; }
	void			VisitNodesChildren();
						
	// $$$ later we should make a falg that is set when the pos is updated
	bool			HasMoved() const {
						return true; }
						
				
	virtual void	Spawn(const Vector2f& i_pos);	//makes an object appear at the location (no placing or constructing)

protected:
	
	void			setProvidesConnection(bool i_on) {
						m_connectionFlags.Provides = i_on; }
	void			setRequiresConnection(bool i_on) {
						m_connectionFlags.Requires = i_on; }
	void			setConnectionsAllowed(int i_connectionsAllowed) {
						m_connectionsAllowed = i_connectionsAllowed; }
						
	virtual	void	on_TouchFocusGained(const Vector2f& i_touchPos, bool& o_usedInput);
	virtual	void	on_TouchFocusMoved(const Vector2f& i_touchPos, bool& o_usedInput);
	virtual	void	on_TouchFocusLost(const Vector2f& i_touchPos, bool& o_usedInput);
	virtual bool	doesHandlesTouch() const {
						return true; }

private:

	void			calculateConnections();
	void			removingFromNodeList();

	//make these structures
	struct SConnectionFlags 
	{
		bool Provides;
		bool Requires;
	};
	

	enum EState
	{
		EState_Placing,			// being placed in the world
		EState_Constructing,	// being constructed
		EState_Connected,		// connected to others with power
		EState_NotConnected,	// not connected to any others
		
	};
	
	
	void			setState(EState i_state);

	float					m_constructionTime;
	float					m_tState;
	EState					m_state;
	SConnectionFlags		m_connectionFlags;
	std::vector<CGoNode*>	m_connections;
	int						m_connectionsAllowed;
	float					m_connectionRadius;
	bool					m_isOrphanedFromRoot;
	bool					m_hasNodeVisited;
	static const CTexture*	m_conntectionTexture;
};

/*-----------------------------------EOF!-----------------------------------*/